import { VRC7Mixer } from "../Audio/VRC7/VRC7Mixer";
import { Bus } from "../Bus";
import { Tile } from "../PPU/PPUBlock";
import { IMapper, MapperInitOption } from "./IMapper";

const PrgMaxAnd = 0x1FFF;

export class Mapper85 implements IMapper {
	bus: Bus;
	prgSize: number = PrgMaxAnd + 1;
	chrSize: number = 0;

	chrRamTile: Tile[][] = [];

	private mixer!: VRC7Mixer;

	constructor(bus: Bus) {
		this.bus = bus;
	}

	Initialization(option: MapperInitOption): void {

		this.bus.cartridge.useSRAM = true;

		this.mixer = new VRC7Mixer(this.bus);
		this.bus.apu.SetExternalSound(this.mixer);

		this.bus.cartridge.prgIndex = [0, 0, 0, option.maxPrg];
		this.bus.cartridge.chrIndex = [0, 0, 0, 0, 0, 0, 0, 0];

		for (let i = 0; i < 8; i++) {
			this.chrRamTile[i] = [];
			for (let j = 0; j < 0x40; j++)
				this.chrRamTile[i][j] = new Tile(new Uint8Array(0x10));
		}
	}

	ReadPRG(address: number): number {
		const index = this.bus.cartridge.prgIndex[(address - 0x8000) >> 13];
		address &= PrgMaxAnd;
		return this.bus.cartridge.prgBanks[index][address];
	}

	WritePRG(address: number, value: number): void {
		switch (address) {
			case 0x8000:
				this.bus.cartridge.prgIndex[0] = value;
				break;
			case 0x8010:
				this.bus.cartridge.prgIndex[1] = value;
				break;
			case 0x9000:
				this.bus.cartridge.prgIndex[2] = value;
				break;
			case 0x9010:
			case 0x9030:
				this.mixer.WriteIO(address, value);
				break;
			case 0xA000:
				this.bus.cartridge.chrIndex[0] = value;
				break;
			case 0xA010:
				this.bus.cartridge.chrIndex[1] = value;
				break;
			case 0xB000:
				this.bus.cartridge.chrIndex[2] = value;
				break;
			case 0xB010:
				this.bus.cartridge.chrIndex[3] = value;
				break;
			case 0xC000:
				this.bus.cartridge.chrIndex[4] = value;
				break;
			case 0xC010:
				this.bus.cartridge.chrIndex[5] = value;
				break;
			case 0xD000:
				this.bus.cartridge.chrIndex[6] = value;
				break;
			case 0xD010:
				this.bus.cartridge.chrIndex[7] = value;
				break;
		}
	}

	ReadCHR(address: number): number {
		const tile = this.GetCHRTile(address >> 4);
		return tile.data[address & 0xF];
	}
	GetCHRTile(tileIndex: number): Tile {
		const index = this.bus.cartridge.chrIndex[tileIndex >> 6];
		tileIndex &= 0x3F;
		if (!this.chrRamTile[index])
			debugger;
		return this.chrRamTile[index][tileIndex];
	}

	WriteCHR(address: number, value: number): void {
		const tile = this.GetCHRTile(address >> 4);
		address &= 0xF;
		tile.SetData(address, value);
	}

	PPUClockEvent?(scanLine: number, ppuCycle: number): void {

	}

}